using Newtonsoft.Json.Linq;
using PP.Basic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

namespace PP.PPPoker.Game.GJ25
{
    /// <summary>
    /// GJ25Layer 对象
    /// </summary>
    public class GJ25Layer : MonoBehaviour
    {
        private const string Tag = nameof(GJ25Layer);
        
        // Private Variables Begin
        private int _currentScore = 0;

        private int MAX_HP = 13;
        private int _currentHp = 13;


        private int MAX_TIME = 140;
        private int _currentTime = 140;

        private AudioPlayTask _audioBGMPlayTask;

        // Private Variables End
        
        // Static Methods Begin
        public static GJ25Layer Create()
        {
            return UIManager.Instance.ShowView<GJ25Layer>("Prefab/GJ25Layer");
        }
        // Static Methods End
        
        // Public Methods Begin
        // Public Methods End


        public void SendMatch()
        {
            var handCards = _handGJCardGroup.GetSelectedCard();
            var boardCards = _boardGJCardGroup.GetSelectedCard();

            // 选牌数量
            if (boardCards.Count == 0)
            {
                _gJToast.Show("Please select Board Card");
                return;
            }
            if (handCards.Count == 0 && boardCards.Count < 5)
            {
                _gJToast.Show("Please select Hand Card");
                return;
            }
            if (handCards.Count + boardCards.Count > 5)
            {
                _gJToast.Show("You can select up to 5 cards");
                return;
            }


            var hCodes = new List<int>();
            for (int i = 0; i < handCards.Count; i++)
            {
                var card = handCards[i];
                hCodes.Add(card.Code);
            }

            var bCodes = new List<int>();
            for (int i = 0; i < boardCards.Count; i++)
            {
                var card = boardCards[i];
                bCodes.Add(card.Code);
            }

            Debug.Log($"Hand Cards: {string.Join(",", hCodes)}");
            Debug.Log($"Board Cards: {string.Join(",", bCodes)}");

            var cardobjs = new List<GJCard>();
            cardobjs.AddRange(handCards);
            cardobjs.AddRange(boardCards);

            StartCoroutine(HttpReqMatchType(bCodes.Concat(hCodes).ToList(), cardobjs));
        }



        public IEnumerator HttpReqMatchType(List<int> codes, List<GJCard> cards)
        {
            string query = string.Join("&", codes.Select(c => $"cards={c}"));
            var url = $"{GameConfig.ServerDomain}/api/confirm?{query}";

            Debug.Log($"{Tag}.# HttpReqType -> url: {url}");
            UnityWebRequest www = UnityWebRequest.Get(url);
            yield return www.SendWebRequest();
            if (www.result == UnityWebRequest.Result.Success)
            { 
                var jsRet = JObject.Parse(www.downloadHandler.text);
                if (jsRet == null)
                {
                    Debug.LogWarning($"{Tag}.pop.check -> result = null ");
                    yield return null;
                }
                int code = (int)jsRet["code"]?.Value<int>();


                int hp = jsRet["hp"]?.Value<int>() ?? 0;
                int card_type = jsRet["card_type"]?.Value<int>() ?? 0;
                int score = jsRet["score"]?.Value<int>() ?? 0;

                // Debug.Log($"{Tag}.# result: {result}");
                if (code == 100)
                {
                    Debug.Log($"{Tag}. Result = {card_type}, {score}, {hp}");
                    var cardType = (GJHandType)card_type;
                    ShowMatchResult(cardType, score, hp, cards);
                }
                else
                {
                    _gJToast.Show($"{Tag}. Result = Failed: {card_type}, {score}, {hp}");
                }
            }
        }


        private void ShowMatchResult(GJHandType hType, int scoreDelta, int hpDelta, List<GJCard> cards)
        {
            // Show the match result to the user
            _currentScore += scoreDelta;
            _currentHp += hpDelta;
            
            Debug.Log($"Match Result: Card Type: {hType}, Score: {scoreDelta}, HP: {hpDelta}");
            Debug.Log($"Current Score: {_currentScore}, Current HP: {_currentHp}");

            this.PlayAudio(AudioConfig.Score);

            // 分数
            _scoreTextTmp.text = _currentScore.ToString();

            // 计算当前血量
            var percentHp = (float)_currentHp / MAX_HP;
            if (percentHp > 1)
                percentHp = 1;
            else if (percentHp < 0)
                percentHp = 0;
            _hPFillImage.fillAmount = percentHp;
            _leftHpTextTmp.text = _currentHp.ToString();

            // 播放血量减少动画
            if (hpDelta < 0)
            {
                _gJHPEffect.PlayHPLoss(hpDelta);
            }


            // 结算效果
            _gJScoreEffect.ShowTypeScore(hType);


            // 发牌
            var totalCount = cards.Count;
            for (int i = 0; i < cards.Count; i++)
            {
                var card = cards[i];
                // 消除牌和生成新牌
                if (totalCount -1 == i)
                {
                    card.PlayRemove(() =>
                    {
                        _handGJCardGroup.Deal(needAnim:true);
                        _boardGJCardGroup.Deal(needAnim:true);

                        CheckIfGameOver();
                    });
                }
                else
                    card.PlayRemove();
            }
        }

        // 检查结束条件 ...
        private void CheckIfGameOver()
        {
            int leftHandCardCount = _handGJCardGroup.GetLeftCard();
            int leftBoardCardCount = _boardGJCardGroup.GetLeftCard();
            int leftDeckCard = CardDealer.Instance.RemainingCount;

            if (_currentHp <= 5)
                _heartEffectTrigger.Play("HeartEffectAlarm", isLoop: true);
            if (_currentTime <= 20)
                _timeEffectTrigger.Play("HeartEffectAlarm", isLoop: true);


            bool isGameOver = false;
            do
            {            // 结束条件: Hp
                if (_currentHp <= 0)
                {
                    Debug.Log($"{Tag}.# Game Over: HP <= 0");
                    isGameOver = true;
                    break;
                }

                if (_currentTime <= 0)
                {
                    Debug.Log($"{Tag}.# Game Over: Time <= 0");
                    isGameOver = true;
                    break;
                }

                // 结束条件: 手牌
                if (leftDeckCard <= 0 && leftHandCardCount + leftBoardCardCount <= 1)
                {
                    Debug.Log($"{Tag}.# Game Over: Deck Card <= 0");
                    isGameOver = true;
                    break;
                }

                if (leftDeckCard <= 0 && (leftHandCardCount <= 0 || leftBoardCardCount <= 0))
                {   
                    Debug.Log($"{Tag}.# Game Over: No Card");
                    isGameOver = true;
                    break;
                }
            } while (false);

            if (isGameOver)
            {
                if (_audioBGMPlayTask.AudioSource != null)
                {
                    _audioBGMPlayTask.Cancel();
                }

                Debug.Log($"{Tag}.# Game Over *************************************************************");
                _oKButton.interactable = false;
                _gameOverGo.SetActive(true);
                this.PlayAudio(AudioConfig.GameOVer);

                StopOVerTimer();

                Scheduler.Instance.DelayedCall(5.0f, () =>
                {
                    StartCoroutine(HttpReqOver(_currentScore, _currentHp, leftHandCardCount + leftBoardCardCount));
                });
            }
            else
            {
                Debug.Log($"{Tag}.# Continue Game");
            }
        }


        // 结束请求
        private IEnumerator HttpReqOver(int score, int leftHp, int leftCard)
        {
            var url = $"{GameConfig.ServerDomain}/api/game_over?player_name={GameManager.Instance.playername}&score={score}&hp={leftHp}&hold_card={leftCard}";

            Debug.Log($"{Tag}.# HttpReqType -> url: {url}");
            Debug.Log($"{Tag}.# HttpReqType -> url: {url}");
            UnityWebRequest www = UnityWebRequest.Get(url);
            yield return www.SendWebRequest();
            if (www.result == UnityWebRequest.Result.Success)
            {
                Debug.Log($"HttpReqOver : {www.downloadHandler.text}");
                var jsRet = JObject.Parse(www.downloadHandler.text);
                if (jsRet == null)
                {
                    Debug.LogWarning($"{Tag}.pop.check -> result = null");
                    yield return null;
                }
                int code = (int)jsRet["code"]?.Value<int>();


                int endingType = jsRet["ending_type"]?.Value<int>() ?? 1;
                int finalScore = jsRet["score"]?.Value<int>() ?? 0;
                int rankNum = jsRet["ranking"]?.Value<int>() ?? 0;

                if (code == 100)
                {
                    Debug.Log($"{Tag}. Result = Score:{finalScore}, Ending:{endingType}, Rank:{rankNum}");
                    ShowEndingView(endingType, finalScore);
                }
                else
                {
                    _gJToast.Show($"{Tag}. Result = Failed XXXXXXXXXXXXXXXXXXX");
                    GJ25LeaderBoard.Create();
                }
            }
        }


        private void ShowEndingView(int endingType, int finalScore)
        {
            GameManager.Instance.endingType = endingType;
            // 跳到结局
            GJEndingLayer.Create(finalScore);

            UIManager.Instance.CloseView<GJ25Layer>();
        }


        private void StartOVerTimer()
        {
            Debug.Log($"StartOVerTimer: start {_leftSecondsTextTmp.name}");
            _leftSecondsTextTmp.Schedule(1.0f, () => 
            {
                Debug.Log($"StartOVerTimer: _currentTime={_currentTime}");
                _currentTime--;
                
                _timeFillImage.fillAmount = (float)_currentTime / MAX_TIME;
                _leftSecondsTextTmp.text = _currentTime.ToString();

                if (_currentTime <= 0)
                {
                    _currentTime = 0;
                    StopOVerTimer();
                    CheckIfGameOver();
                }
            });
        }

        private void StopOVerTimer()
        {
            _leftSecondsTextTmp.Unschedule();
        }




        
        // Lifecycle Methods Begin
        protected void Awake()
        {
            Debug.Log($"{Tag}.Awake");

            InitHier();
            InitPart();
        }

        private void InitPart()
        {
            // Do initialization here...
            _gJScoreEffect.gameObject.SetActive(false);
            _gJHPEffect.gameObject.SetActive(false);

            _gJToast.gameObject.SetActive(false);

            _gameOverGo.SetActive(false);
        }
        
        private void Start()
        {
            Debug.Log($"{Tag}.Start");

            CardDealer.Instance.ResetDeck();

            _scoreTextTmp.text = "0";

            _currentHp = MAX_HP;
            _hPFillImage.fillAmount = 1;
            _leftHpTextTmp.text = _currentHp.ToString();

            _currentTime = MAX_TIME;
            _timeFillImage.fillAmount = 1;
            _leftSecondsTextTmp.text = _currentTime.ToString();

            _handGJCardGroup.Deal();
            _boardGJCardGroup.Deal();

            StartOVerTimer();

            _audioBGMPlayTask = this.PlayAudio(AudioConfig.BGM, isLoop:true);

            // GJ25LeaderBoard.Create();
        }
        protected void OnDestroy()
        {
            Debug.Log($"{Tag}.OnDispose");

            if (_audioBGMPlayTask.AudioSource != null)
            {
                _audioBGMPlayTask.Cancel();
            }
            Debug.Log($"{Tag}.# Stop Audio GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG");
            
            // Do cleanups here...
            // Stop animations! Cancel global callbacks ...
        }
        // Lifecycle Methods End


        // Hier Components Begin        
        private Image _backgroundImage;
        private Button _oKButton;
        private GJCardGroup _boardGJCardGroup;
        private GJCardGroup _handGJCardGroup;
        private Image _hPFillImage;
        private TMP_Text _leftHpTextTmp;
        private GJHPEffect _gJHPEffect;
        private Image _timeFillImage;
        private TMP_Text _leftSecondsTextTmp;
        private TMP_Text _scoreTextTmp;
        private GJScoreEffect _gJScoreEffect;
        private GameObject _gameOverGo;
        private GJToast _gJToast;
        private Button _ruleButton;

        private AnimationTrigger _heartEffectTrigger;
        private AnimationTrigger _timeEffectTrigger;

        private void InitHier()
        {
            _backgroundImage = transform.Find("_Image_Background").GetComponent<Image>();
            _oKButton = transform.Find("_Button_OK").GetComponent<Button>();
            _oKButton.onClick.AddListener(OnOKButtonClick);
            _boardGJCardGroup = transform.Find("_GJCardGroup_Board#").GetComponentEx<GJCardGroup>();
            //_boardGJCardGroup.Initiate();
            _handGJCardGroup = transform.Find("_GJCardGroup_Hand#").GetComponentEx<GJCardGroup>();
            //_handGJCardGroup.Initiate();
            _hPFillImage = transform.Find("Image_perccentHP/_Image_HPFill").GetComponent<Image>();
            _leftHpTextTmp = transform.Find("Image_perccentHP/_TextTmp_leftHp").GetComponentEx<TMP_Text>();
            _gJHPEffect = transform.Find("Image_perccentHP/_GJHPEffect#").GetComponentEx<GJHPEffect>();
            //_gJHPEffect.Initiate();
            _timeFillImage = transform.Find("Image_perccentTime/_Image_TimeFill").GetComponent<Image>();
            _leftSecondsTextTmp = transform.Find("Image_perccentTime/_TextTmp_leftSeconds").GetComponentEx<TMP_Text>();
            _scoreTextTmp = transform.Find("Image_Score/_TextTmp_Score").GetComponentEx<TMP_Text>();
            _gJScoreEffect = transform.Find("_GJScoreEffect#").GetComponentEx<GJScoreEffect>();
            //_gJScoreEffect.Initiate();
            _gameOverGo = transform.Find("_Go_GameOver").gameObject;
            _gJToast = transform.Find("_GJToast#").GetComponentEx<GJToast>();
            //_gJToast.Initiate();

            _ruleButton = transform.Find("_Button_Rule").GetComponent<Button>();
            _ruleButton.onClick.AddListener(OnRuleButtonClick);


            _heartEffectTrigger = transform.Find("Image_perccentHP/_AnimationTrigger_HeartEffect").GetComponentEx<AnimationTrigger>();
            _timeEffectTrigger = transform.Find("Image_perccentTime/_AnimationTrigger_TimeEffect").GetComponentEx<AnimationTrigger>();
        }

        private void OnRuleButtonClick()
        {
            GJRuleLayer.Create();
        }
        private void OnOKButtonClick()
        {
            SendMatch();
        }
        // Hier Components End

        // Hier Components End



    }
}
